package com.mdnote.structure.stack;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 * @author Rhythm-2019
 * @version 1.0
 * @date 2020/8/24
 * @description  中缀表达式计算器
 */
public class InfixExpressionCalc {

    // 表达式
    private String express;

    // 操作数字和符号的几何
    private List<String> items;

    public InfixExpressionCalc(String express) {
        this.express = express;
        this.items = convert(express);
    }

    private List<String> convert(String express) {
        List<String> rtn = new ArrayList<>();

        int index = 0;
        do {
            if (express.charAt(index) >= 48 && express.charAt(index) <= 57) {
                // 如果是数字，|看看是不是多位数
                String tmp = "";
                while (index < express.length() && express.charAt(index) >= 48 && express.charAt(index) <= 57) {
                    tmp += express.substring(index, index + 1);
                    index ++;
                }
                rtn.add(tmp);
            } else {
                // 如果是符号，直接add
                rtn.add(express.substring(index, index + 1));
                index ++;
            }
        } while (index < express.length());

        return rtn;
    }

    public int calculate() {
        // 创建两个栈
        Stack<Integer> numberStack = new Stack<>();
        Stack<Character> operationStack = new Stack<>();
        // 遍历表达式、
        for (String item : this.items) {
            if (item.charAt(0) < 48 || item.charAt(0) > 57) {
                // 如果是符号，判断栈是否为空
                if (operationStack.isEmpty()) {
                    // 为空，直接入栈
                    operationStack.push(item.charAt(0));
                } else {
                    // 不为空，判断优先级
                    while (!operationStack.isEmpty() && !Operation.comparePriority(item.charAt(0), operationStack.peek())) {
                        // 当前符号优先级低，弹出一个符号和两个数字，运算后压回数字的栈
                        Character operation = operationStack.pop();
                        Integer n1 = numberStack.pop();
                        Integer n2 = numberStack.pop();
                        // 数字的栈最后的数字就是答案
                        // 注意是下面的数字 - / 上面的数字
                        numberStack.push(Operation.calculate(n2, n1, operation));
                    }
                    // 吧操作数放近期
                    operationStack.push(item.charAt(0));
                }

            } else {
                // 如果是数字 直接加入数字的栈、
                numberStack.push(Integer.valueOf(item));
            }
        }

        // 最后不断拿出两个数字和一个操作符进行计算
        while (!operationStack.isEmpty()) {
            Character operation = operationStack.pop();
            Integer n1 = numberStack.pop();
            Integer n2 = numberStack.pop();
            numberStack.push(Operation.calculate(n2, n1, operation));
        }

        return numberStack.peek();
    }

    public static void main(String[] args) {
        InfixExpressionCalc infixExpressionCalc = new InfixExpressionCalc("11*22/11-22");
        System.out.println(infixExpressionCalc.calculate());

    }


}
